#include "ffmpeg_config.h"

// 配置FFMPEG编解码器的属性
int add_stream(AVFormatContext *fmt_ctx, OutputStream *ost, const AVCodec **codec, enum AVCodecID codec_id, int width, int heiht)
{
    int ret = -1;
    AVCodecContext *ctx = NULL;
    ost->stream = avformat_new_stream(fmt_ctx, NULL); // 创建输出码流的AVStream,用于存储相关音视频的信息
    if (!ost->stream)
    {
        cout << "Create new stream failed ..." << endl;
        return -1;
    }
    else
    {
        cout << "Create new stream success ..." << endl;
    }
    cout << "codec_id is..." << codec_id << endl;
    *codec = avcodec_find_encoder(codec_id); // 获取相应的编解码器实列
    if (!(*codec))
    {
        cout << "avcodec_find_encoder failed ..." << endl;
        return -1;
    }
    else
    {
        cout << "avcodec_find_encoder success ..." << endl;
    }

    ost->stream->id = fmt_ctx->nb_streams - 1; // 设置输出流的索引号
    ctx = avcodec_alloc_context3(*codec);      // 根据分配的codec实例化出对应AVCodecContext;
    if (!ctx)
    {
        cout << "avcodec_alloc_context3 failed ..." << endl;
        return -1;
    }
    else
    {
        cout << "avcodec_alloc_context3 success ..." << endl;
    }

    ost->ctx = ctx; // 将实例化的AVCodecContext赋给OutputStream结构中的ctx;

#if 0
                        const char *codec_name = "h264_rkmpp";
                        const AVCodec *codecss = avcodec_find_encoder_by_name(codec_name);
                        if (!codecss) {
                            printf("Codec '%s' not found\n", codec_name);
                            return -1;
                        }
                        printf("Supported pixel formats for %s:\n", codec_name);
                
                        const enum AVPixelFormat *p = codecss->pix_fmts;
                        if (p) {
                            while (*p != AV_PIX_FMT_NONE) {
                                printf("%s\n", av_get_pix_fmt_name(*p));
                                p++;
                            }
                        } else {
                            printf("No specific pixel format restrictions, defaulting to all available formats.\n");
                        }
#endif

    switch ((*codec)->type)
    {
    case AVMEDIA_TYPE_VIDEO:
        cout << "codec type is AVMEDIA_TYPE_VIDEO..." << endl;

        ctx->time_base = (AVRational){1, 30}; // 设置编码器的的时间基
        ctx->gop_size = 30;
        ctx->pix_fmt = AV_PIX_FMT_NV12;

        ctx->bit_rate = width * heiht * 3;
        ctx->width = width;
        ctx->height = heiht;
        break;

    case AVMEDIA_TYPE_AUDIO:
        cout << "codec type is AVMEDIA_TYPE_AUDIO..." << endl;
        ctx->sample_fmt = AV_SAMPLE_FMT_FLTP;

        ctx->bit_rate = 128000;
        ctx->sample_rate = 48000;
        ctx->channel_layout = AV_CH_LAYOUT_STEREO;                              // FFMPEG声道数2
        ctx->channels = av_get_channel_layout_nb_channels(ctx->channel_layout); // FFMPEG采样通道
        //ost->stream->time_base = (AVRational){1, 48000};
        ctx->time_base = (AVRational){1, 48000};
        break;

    default:
        cout << "No codec type ..." << endl;
        break;
    }

    if (fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) // 在h264头部添加SPS，PPS //AVOutputFormat
    {
        ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; // 设置AVCodecContext的头部信息，告诉编码器生成全局头部信息
    }
    return 0;
}

// 使能video编码器
int open_video(AVFormatContext *fmt_ctx, OutputStream *ost, const AVCodec *codec)
{
    int ret = -1;
    ret = avcodec_open2(ost->ctx, codec, NULL);
    if (ret)
    {
        cout << "avcodec_open2 failed ..." << endl;
        return -1;
    }
    else
    {
        cout << "avcodec_open2 success ..." << endl;
    }

    ost->pkt = av_packet_alloc(); // 实例化出相应的AVPacket包，很重要
    if (ost->pkt == NULL)
    {
        cout << "av_packet_alloc failed ..." << endl;
    }
    else
    {
        cout << "av_packet_alloc success ..." << endl;
    }

    ret = avcodec_parameters_from_context(ost->stream->codecpar, ost->ctx); // 将编码器上下文的参数复制到流的编解码参数中
    if (ret < 0)
    {
        cout << "avcodec_parameters_from_context failed ..." << endl;
        return -1;
    }
    else
    {
        cout << "avcodec_parameters_from_context success ..." << endl;
    }

    return 0;
}

int open_audio(AVFormatContext *fmt_ctx, OutputStream *ost, const AVCodec *codec)
{
    int ret = -1;

    ret = avcodec_open2(ost->ctx, codec, NULL);
    if (ret)
    {
        cout << "audio avcodec_open2 failed ..." << endl;
        return -1;
    }
    else
    {
        cout << "audio avcodec_open2 success ..." << endl;
    }

    ost->pkt = av_packet_alloc(); // 实例化出相应的AVPacket包，很重要
    if (ost->pkt == NULL)
    {
        cout << "audio av_packet_alloc failed ..." << endl;
        return -1;
    }
    else
    {
        cout << "audio av_packet_alloc success ..." << endl;
    }

    ret = avcodec_parameters_from_context(ost->stream->codecpar, ost->ctx); // 将编码器上下文的参数复制到流的编解码参数中
    if (ret < 0)
    {
        cout << "audio avcodec_parameters_from_context failed ..." << endl;
        return -1;
    }
    else
    {
        cout << "audio avcodec_parameters_from_context success ..." << endl;
    }

    return 0;
}

int free_stream(OutputStream *ost)
{
    if (ost->ctx)
    {
        // avcodec_close(ost->ctx); // 关闭编码器的AVCodecContext,这个已经弃用用下面avcodec_free_context
        avcodec_free_context(&(ost->ctx)); // 释放AVCodecContext上下文
    }
    if (ost->pkt)
    {
        av_packet_unref(ost->pkt);   // 释放AVPacket关联的缓冲区(AVStreamRef引用计数 -1),清空引用缓冲区的数据，但不会释放AVPacket本身
        av_packet_free(&(ost->pkt)); // 释放AVPacket本身
    }
    cout << "this is free_stream operate ..." << endl;
    return 0;
}

#if 1
int init_rkmedia_ffmpeg_context(ffmpegInfo *ffmpeg_config)
{
    int ret = -1;
    const AVCodec *video_codec = NULL;
    const AVCodec *audio_codec = NULL;

    if (ffmpeg_config->protocol == FLV_PROTOCOL) // FLV_PROTOCOL is RTMP TCP
    {

        ret = avformat_alloc_output_context2(&ffmpeg_config->fmt_ctx, NULL, "flv", ffmpeg_config->nAddr); // 实列化相应的AVFormatContext
        if (ret)
        {
            cout << "avformat_alloc_output_context2 flv failed ..." << endl;
            return -1;
        }
        else
        {
            cout << "avformat_alloc_output_context2 flv success ..." << endl;
        }
    }

    if (ffmpeg_config->video_codec == AV_CODEC_ID_H264)
    {
        ret = add_stream(ffmpeg_config->fmt_ctx, &ffmpeg_config->video_stream, &video_codec, ffmpeg_config->video_codec, ffmpeg_config->u32Width, ffmpeg_config->u32Height);
        if (ret)
        {
            cout << "add_stream failed ..." << endl;
            free_stream(&ffmpeg_config->video_stream);
            avformat_free_context(ffmpeg_config->fmt_ctx);
            return -1;
        }
        else
        {
            cout << "add_stream success ..." << endl;
        }

        ret = open_video(ffmpeg_config->fmt_ctx, &ffmpeg_config->video_stream, video_codec); // 这里的AVCodec video_codec是一个传入传出参数，以便获取相应的编解码器实列
        if (ret)
        {
            cout << "open_video failed ..." << endl;
            free_stream(&ffmpeg_config->video_stream);
            avformat_free_context(ffmpeg_config->fmt_ctx);
            return -1;
        }
        else
        {
            cout << "open_video success ..." << endl;
        }
    }

    if (ffmpeg_config->audio_codec == AV_CODEC_ID_AAC)
    {
        ret = add_stream(ffmpeg_config->fmt_ctx, &ffmpeg_config->audio_stream, &audio_codec, ffmpeg_config->audio_codec, ffmpeg_config->u32Width, ffmpeg_config->u32Height);
        if (ret)
        {
            cout << "audio add_stream failed ..." << endl;
            free_stream(&ffmpeg_config->audio_stream);
            avformat_free_context(ffmpeg_config->fmt_ctx);
            return -1;
        }
        else
        {
            cout << "audio add_stream success ..." << endl;
        }

        ret = open_audio(ffmpeg_config->fmt_ctx, &ffmpeg_config->audio_stream, audio_codec); // 这里的AVCodec audio_codec是一个传入传出参数，以便获取相应的编解码器实列
        if (ret)
        {
            cout << "open_audio failed ..." << endl;
            free_stream(&ffmpeg_config->audio_stream);
            avformat_free_context(ffmpeg_config->fmt_ctx);
            return -1;
        }
        else
        {
            cout << "open_audio success ..." << endl;
        }
    }

    av_dump_format(ffmpeg_config->fmt_ctx, 0, ffmpeg_config->nAddr, 1); // 打印输出格式的信息，调试用的...

    if (!(ffmpeg_config->fmt_ctx->oformat->flags & AVFMT_NOFILE))
    {
        ret = avio_open(&ffmpeg_config->fmt_ctx->pb, ffmpeg_config->nAddr, AVIO_FLAG_WRITE); // 开启输出流
        if (ret < 0)
        {
            cout << "avio_open failed ..." << endl;
            free_stream(&ffmpeg_config->video_stream);
            free_stream(&ffmpeg_config->audio_stream);
            avformat_free_context(ffmpeg_config->fmt_ctx);
            return -1;
        }
        else
        {
            cout << "avio_open success ..." << endl;
        }
    }
    ret = avformat_write_header(ffmpeg_config->fmt_ctx, NULL); // 写入头部信息

    if (ret < 0)
    {
        cout << "avformat_write_header failed ..." << endl;
        return -1;
    }
    return 0;
}
#endif